﻿using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;
using Might.Infrastructure.Annotations.Graphics;

namespace Might.GraphicsEditor.GraphicsObjects {
    /// <summary>
    /// Class representation for simple ellipse
    /// </summary>
    public class LeafEllipse : GraphicsLeaf {
        internal EllipseGeometry ellipse;
        internal PathGeometry ellipseEx;
        internal double startA, endA;

        /// <summary>
        /// Public constructor for simple ellipse
        /// </summary>
        /// <param name="ga">Graphic annotation for this object</param>
        public LeafEllipse(IGraphicsItem ga) {
            this.ga = ga;
            startA = endA = -1;
            ellipse = new EllipseGeometry {
                Center = new Point(100, 100),
                RadiusX = 100,
                RadiusY = 100
            };
            ellipseEx = GetPathEllipse();

            Path = new Path {
                StrokeLineJoin = PenLineJoin.Bevel,
                Stretch = Stretch.Fill
            };
            Content = Path;

            UpdateShape();

            this.ga.Changed += GaGraphicsPrimitiveChanged;
        }

        protected override void UpdateShape() {
            base.UpdateShape();
            IGraphicsEllipse g = ga as IGraphicsEllipse;
            if (g == null) {
                throw new NullReferenceException("Updating Null anotation");
            }
            if (startA != g.StartAngle || endA != g.EndAngle) {
                startA = g.StartAngle;
                endA = g.EndAngle;
                if (AnglesEqual(g.StartAngle, g.EndAngle)) {
                    Path.Data = ellipse;
                } else {
                    UpdatePathEllipse(g.StartAngle, g.EndAngle);
                    Path.Data = ellipseEx;
                }
            }
        }

        private Rect UpdatePathEllipse(double startAngle, double endAngle) {
            const double pieRadius = 100;
            Rect r = new Rect(pieRadius, pieRadius, 0, 0);
            startAngle %= 360;
            endAngle %= 360;

            Point A = GetCircumferencePoint(startAngle, pieRadius, pieRadius);
            Point C = GetCircumferencePoint(endAngle, pieRadius, pieRadius);
            r.Union(A);
            r.Union(C);

            bool isReversed = startAngle > endAngle;
            bool isReflexAngle = isReversed ^ Math.Abs(endAngle - startAngle) > 180.0;
            if ((startAngle <= 90 && endAngle >= 90) ^ isReversed) {
                r.Union(new Point(pieRadius, 0));
            }
            if ((startAngle <= 180 && endAngle >= 180) ^ isReversed) {
                r.Union(new Point(0, pieRadius));
            }
            if ((startAngle <= 270 && endAngle >= 270) ^ isReversed) {
                r.Union(new Point(pieRadius, pieRadius*2));
            }
            if ((startAngle < 360 && endAngle >= 0) ^ isReversed) {
                r.Union(new Point(pieRadius*2, pieRadius));
            }

            PathFigure pf = ellipseEx.Figures[0];
            pf.StartPoint = A;
            ((LineSegment) pf.Segments[1]).Point = C;
            ((ArcSegment) pf.Segments[2]).Point = A;
            ((ArcSegment) pf.Segments[2]).IsLargeArc = isReflexAngle;
            return r;
        }

        private static PathGeometry GetPathEllipse() {
            PathGeometry data = new PathGeometry {
                Figures = new PathFigureCollection {
                    new PathFigure {
                        IsClosed = true,
                        StartPoint = new Point(),
                        Segments = new PathSegmentCollection {
                            new LineSegment {Point = new Point(100, 100)},
                            new LineSegment {Point = new Point()},
                            new ArcSegment {
                                Size = new Size(100, 100),
                                Point = new Point(),
                                SweepDirection = SweepDirection.Clockwise
                            }
                        }
                    }
                }
            };

            return data;
        }

        private static Point GetCircumferencePoint(double angle, double radiusX, double radiusY) {
            double angleRad = (Math.PI/180.0)*angle;

            double x = radiusX + Math.Max(radiusX, 0)*Math.Cos(angleRad);
            double y = radiusY + Math.Max(radiusY, 0)*-Math.Sin(angleRad);

            return new Point(x, y);
        }

        private static bool AnglesEqual(double a, double b) {
            return a%360 == b%360;
        }
    }
}
